package com.uinnova.product.eam.init.cmdb;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.uinnova.product.eam.model.dto.CiCodeDto;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.IEamCIClassApiSvc;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.base.SaveBatchCIContext;
import com.uino.dao.util.ESUtil;
import com.uino.service.cmdb.microservice.impl.CIClassSvc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @description: cmdb数据同步
 * @author: LiMG
 * @create: 2024-05-22 09:27:54
 **/
@Slf4j
@Service
public class SyncCmdbSvc {

    @Autowired
    private CIClassSvc ciClassSvc;

    @Autowired
    private ICISwitchSvc iciSwitchSvc;

    @Autowired
    IEamCIClassApiSvc ciClassApiSvc;

    /**
     * cmdb请求IP地址
     */
    private static String HOST;

    /**
     * cmdb的access_key
     */
    private static String ACCESS_KEY;

    /**
     * cmdb的secret_key
     */
    private static String SECRET_KEY;

    /**
     * cmdb数据获取接口地址
     */
    private static String INTERFACE_URL;

    /**
     * cmdb数据获取接口每页条数
     */
    private static Integer PAGE_SIZE = 200;

    /**
     * EA中需要同步数据的对象分类集合
     */
    private static JSONArray categoryArray;

    /**
     * 总页码
     */
    private static int TOTAL_PAGE;

    /**
     * cmdb的分类配置
     */
    private static JSONObject CATEGORY_CONFIG;

    /**
     * 分类字段映射集合
     */
    private static JSONObject FIELD_MAPPING;

    /**
     * 子类的cmdb的分类配置
     */
    private static JSONObject CHILD_CATEGORY_CONFIG;

    /**
     * 子类字段映射集合
     */
    private static JSONObject CHILD_FIELD_MAPPING;

    /**
     * 子类匹配规则
     */
    private static Map<String,Map<String,String>> CHILD_RULES_MAP = new HashMap<>();

    /**
     * 父类匹配规则
     */
    private static Map<String,Map<String,String>> RULES_MAP = new HashMap<>();

    /**
     * 获取到的cmdb数据集合
     */
    private static List<JSONObject> CMDB_DATA_LIST;

    private static final String VIEW_NAME = "视图配置中CMDB业务系统&子系统数据同步配置";

    /**
     * 人员字段集合
     */
    private static List<String> PERSON_FIELD_LIST;

    /**
     * 部門字段集合
     */
    private static JSONObject DEP_FIELD_MAPPING;

    /**
     * 不覆盖的字段
     */
    private static List<String> NO_COVER_FIELD;

    /**
     * 同步cmdb数据
     *
     * @param jsonConfig
     */
    public void syncCmdbData(JSONObject jsonConfig) {
        // 校验视图配置中的配置项
        checkSyncConfig(jsonConfig);
        // 根据配置的分类集合循环遍历同步数据
        for (int i = 0; i < categoryArray.size(); i++) {
            // 要对接数据的EA系统分类
            syncByCategoryArray(jsonConfig, categoryArray.getString(i));
        }
    }


    public void syncByCategoryArray(JSONObject jsonConfig,String category) {

        // 根据视图配置中的配置项获取EA系统中对应的对象分类
        CCcCiClass classCdt = new CCcCiClass();
        classCdt.setClassCodes(new String[]{category});
        // 查询EA系统中对应的对象分类
        List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryClassByCdt(classCdt);
        if (null == ccCiClassInfos || ccCiClassInfos.size() == 0) {
            log.info("EA系统中不存在[{}]的对象分类", category);
            return;
        }
        // 从对象分类中筛选出分类和分类ID的map集合
        Map<String, CcCiClassInfo> map = ccCiClassInfos.stream().collect(Collectors.toMap(item -> item.getCiClass().getClassCode(), item->item));


        JSONArray all = jsonConfig.getJSONArray("cmdb_category_types");
        JSONObject targetObject = null;

        // 遍历JSONArray查找匹配的对象
        for (int i = 0; i < all.size(); i++) {
            JSONObject item = all.getJSONObject(i);
            if (item.getString("name").equals(category)) {
                CATEGORY_CONFIG = item;
                break;
            }
        }

        if(CATEGORY_CONFIG.getJSONObject("childCategory") != null){
            String childName = CATEGORY_CONFIG.getJSONObject("childCategory").getString("name");
            Map<String, String> rulesMap = CATEGORY_CONFIG.getJSONObject("childCategory").getObject("rules", Map.class);
            CHILD_RULES_MAP.put(childName,rulesMap);
            RULES_MAP.put(category,rulesMap);
            syncByCategoryArray(jsonConfig,childName);

            // 遍历JSONArray查找匹配的对象
            for (int i = 0; i < all.size(); i++) {
                JSONObject item = all.getJSONObject(i);
                if (item.getString("name").equals(category)) {
                    CATEGORY_CONFIG = item;
                    break;
                }
            }
        }


        Assert.isTrue(null != CATEGORY_CONFIG, category + "未找到该分类的cmdb_category_types配置");

        FIELD_MAPPING = CATEGORY_CONFIG.getJSONObject("fieldMapping");
        PERSON_FIELD_LIST = jsonConfig.getObject("personFiledList", List.class);

        DEP_FIELD_MAPPING = jsonConfig.getJSONObject("depFiledMapping");

        List<JSONObject> noCoverList = jsonConfig.getObject("no_cover_filed_list", List.class);
        noCoverList = noCoverList.stream().filter(bean->category.equals(bean.getString("name"))).collect(Collectors.toList());
        if(noCoverList != null && noCoverList.size() >0){
            NO_COVER_FIELD = noCoverList.get(0).getObject("filed", List.class);
        }

        // 获取cmdb数据
        List<JSONObject> cmdbList = getCmdbData(1);
        if (null == cmdbList || cmdbList.size() == 0) {
            log.info("获取cmdb[{}]数据为空，不做处理", category);
            return;
        }
//            // 本地测试数据
//            localTestData();
        List<ESCIInfo> list = dealCmdbData(map, category,jsonConfig);
        log.info("分类[{}]数据同步开始，共{}条数据", category, list.size());


        int batchSize = 3000;
        // 创建原始列表的副本
        List<ESCIInfo> originalSaveUserList = new ArrayList<>(list);
        int totalSize = originalSaveUserList.size();
        // 使用 double 类型避免整数除法问题
        int batchCount = (int) Math.ceil((double) totalSize / batchSize);

        log.info("应用程序总条数:{}", totalSize);

        for (int i = 0; i < batchCount; i++) {
            log.info("开始同步第{}批次数据", i);
            int start = i * batchSize;
            int end = Math.min(start + batchSize, totalSize);
            log.info("开始索引:{}, 结束索引:{}", start, end);
            List<ESCIInfo> tmpList = originalSaveUserList.subList(start, end);
            // 使用列表副本，防止list被篡改
            Map<String, ? extends SaveBatchCIContext> resultMap = iciSwitchSvc.saveOrUpdateBatchCIWithoutCIOpLog(new ArrayList<>(tmpList), Arrays.asList(map.get(category).getCiClass().getId()), "admin", "admin", LibType.DESIGN);
            Set<String> keys = resultMap.keySet();
            int addCount = 0;
            int updateCount = 0;
            for (String key : keys) {
                SaveBatchCIContext context = resultMap.get(key);
                if (context.isAdd()) {
                    addCount += 1;
                } else {
                    updateCount += 1;
                }
            }
            log.info("分类[{}]，第{}批次数据同步成功，共{}条数据，插入{}条数据，更新{}条数据",i, category, list.size(), addCount, updateCount);
        }

//        Map<String, ? extends SaveBatchCIContext> resultMap = iciSwitchSvc.saveOrUpdateBatchCIWithoutCIOpLog(list, Arrays.asList(map.get(category).getCiClass().getId()), "admin", "admin", LibType.DESIGN);
//        Set<String> keys = resultMap.keySet();
//        int addCount = 0;
//        int updateCount = 0;
//        for (String key : keys) {
//            SaveBatchCIContext context = resultMap.get(key);
//            if (context.isAdd()) {
//                addCount += 1;
//            } else {
//                updateCount += 1;
//            }
//        }
//        log.info("分类[{}]数据同步成功，共{}条数据，插入{}条数据，更新{}条数据", category, list.size(), addCount, updateCount);
    }
    /**
     * 校验同步配置项
     *
     * @param jsonConfig
     * @return
     */
    private void checkSyncConfig(JSONObject jsonConfig) {
        JSONObject cmdbConfig = jsonConfig.getJSONObject("cmdb_config");
        Assert.isTrue(null != cmdbConfig, VIEW_NAME + "未找到cmdb_config相关配置");
        HOST = cmdbConfig.getString("server_ip");
        ACCESS_KEY = cmdbConfig.getString("access_key");
        SECRET_KEY = cmdbConfig.getString("screct_key");
        INTERFACE_URL = cmdbConfig.getString("interface_url");
        PAGE_SIZE = null == cmdbConfig.getInteger("page_size") ? PAGE_SIZE : cmdbConfig.getInteger("page_size");
        Assert.isTrue(StrUtil.isNotEmpty(HOST), VIEW_NAME + "未找到cmdb的server_ip配置");
        Assert.isTrue(StrUtil.isNotEmpty(ACCESS_KEY), VIEW_NAME + "未找到cmdb的access_key配置");
        Assert.isTrue(StrUtil.isNotEmpty(SECRET_KEY), VIEW_NAME + "未找到cmdb的screct_key配置");
        Assert.isTrue(StrUtil.isNotEmpty(INTERFACE_URL), VIEW_NAME + "未找到cmdb的interface_url配置");
        categoryArray = jsonConfig.getJSONArray("ea_category_types");
        Assert.isTrue(null != categoryArray && categoryArray.size() != 0, VIEW_NAME + "未找到对象分类配置");
        JSONArray cmdbCategoryTypes = jsonConfig.getJSONArray("cmdb_category_types");
        Assert.isTrue(null != cmdbCategoryTypes, VIEW_NAME + "未找到cmdb_category_types配置");
//        Assert.isTrue(categoryArray.size() == cmdbCategoryTypes.size(), VIEW_NAME + "下ea_category_types和cmdb_category_types数量不匹配");
        for (int i = 0; i < cmdbCategoryTypes.size(); i++) {
            JSONObject jsonObject = cmdbCategoryTypes.getJSONObject(i);
            String name = jsonObject.getString("name");
            String code = jsonObject.getString("code");
            JSONObject fieldMapping = jsonObject.getJSONObject("fieldMapping");
            Assert.isTrue(StrUtil.isNotEmpty(name), VIEW_NAME + "下cmdb_category_types未找到第[" + (i + 1) + "]个name名称配置");
            Assert.isTrue(StrUtil.isNotEmpty(code), VIEW_NAME + "下cmdb_category_types未找到第[" + (i + 1) + "]个code标识码配置");
            Assert.isTrue(null != fieldMapping, VIEW_NAME + "下cmdb_category_types未找到第[" + (i + 1) + "]个fieldMapping字段映射配置");
        }
    }

    /**
     * 获取cmdb数据
     *
     * @param pageNum
     * @return
     */
    private List<JSONObject> getCmdbData(int pageNum) {
        EasyOps2 easyOps2 = new EasyOps2(HOST, ACCESS_KEY, SECRET_KEY);
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("page", pageNum);
        paramMap.put("page_size", PAGE_SIZE);
        Map<String, Boolean> fieldsMap = new HashMap<>();
        FIELD_MAPPING.keySet().forEach(key -> {
            fieldsMap.put(FIELD_MAPPING.getString(key), true);
        });
        paramMap.put("fields", fieldsMap);
        String categoryCode = CATEGORY_CONFIG.getString("code");
        // 根据分类配置的code码替换查询接口参数
        String result = easyOps2.sendRequest(INTERFACE_URL.replace("@model_id", categoryCode), paramMap, "POST");
        JSONObject jsonObject = JSONObject.parseObject(result);
        // 接口返回状态码
        Integer code = jsonObject.getInteger("code");
        // 接口返回消息
        String message = jsonObject.getString("message");
        // 接口返回错误信息
        String error = jsonObject.getString("error");
        if (code == 0) {
            // 接口调用成功
            JSONObject data = jsonObject.getJSONObject("data");
            if (pageNum == 1) {
                Long total = data.getLong("total");
                // 获取总页码
                TOTAL_PAGE = (int) Math.ceil(total / PAGE_SIZE);
                // 初始化cmdb数据集合
                CMDB_DATA_LIST = new ArrayList<>();
            }
            // 将数据放到集合中
            CMDB_DATA_LIST.addAll(data.getJSONArray("list").toJavaList(JSONObject.class));
            if (pageNum <= TOTAL_PAGE) {
                // 递归调用获取所有数据
                getCmdbData(pageNum + 1);
            }
            return CMDB_DATA_LIST;
        } else {
            log.error("接口调用失败: 返回code码为{}，返回消息为{}，返回错误信息为{}", code, message, error);
            throw new RuntimeException("接口调用失败");
        }
    }


    /**
     * 处理cmdb数据
     *
     * @return
     */
    private List<ESCIInfo> dealCmdbData(Map<String, CcCiClassInfo> map, String category,JSONObject jsonConfig) {
        Assert.isTrue(null != CMDB_DATA_LIST && CMDB_DATA_LIST.size() > 0, "获取到的分类[" + category + "]数据为空，不做处理");
        List<ESCIInfo> list = new ArrayList<>();
        // 定义分类对象
        ESCIInfo info;
        // 定义分类对象属性集合
        Map<String, Object> attrsMap;
        JSONObject fieldMapping = CATEGORY_CONFIG.getJSONObject("fieldMapping");
        // 查询已存在的数据
        CCcCi cc = new CCcCi();
        cc.setClassId(map.get(category).getCiClass().getId());

        /**
         * 获取该分类的字段定义映射
         */
        Map<String, CcCiAttrDef> attrDefMap = map.get(category).getAttrDefs().stream().collect(Collectors.toMap(item -> item.getProName(), item -> item));
        /**
         * 获取 是主键且类型为编码的 字段名称列表
         */
        List<String> mustAttrDefList = map.get(category).getAttrDefs().stream().filter(item->item.getIsRequired() == 1 && item.getIsMajor() == 1 && item.getProType() == 150).map(item->item.getProName()).collect(Collectors.toList());
        /**
         * 获取 类型为所属资产的字段
         */
        List<String> assetsAttrDefList = map.get(category).getAttrDefs().stream().filter(item-> item.getProType() == 19).map(item->item.getProDropSourceDef()).collect(Collectors.toList());


        /**
         * 获取 类型为所属资产的字段
         */
        Map<String,String> assetsAttrDefMap = map.get(category).getAttrDefs().stream().filter(item-> item.getProType() == 19).collect(Collectors.toMap(item->item.getProName(), item->item.getProDropSourceDef()));


        /**
         * 获取 是必填且类型不为编码的 字段名称列表
         */
        List<String> isRequiredAttrDefList = map.get(category).getAttrDefs().stream().filter(item->item.getIsRequired() == 1 && item.getProType() != 150).map(item->item.getProName()).collect(Collectors.toList());

        List<ESCIInfo> exists = iciSwitchSvc.queryESCIInfoList(1L, cc, null, true, LibType.DESIGN);


//        Map<String, ESCIInfo> systemCollect = null;
//        if(category.contains("应用程序")){
//            CCcCiClass classCdt = new CCcCiClass();
//
//            classCdt.setId(Long.valueOf(assetsAttrDefList.get(0)));
//
//            // 查询EA系统中对应的对象分类
//            List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryClassByCdt(classCdt);
////        if (null == ccCiClassInfos || ccCiClassInfos.size() == 0) {
////            log.info("EA系统中不存在[{}]的对象分类", category);
////            return;
////        }
//            // 从对象分类中筛选出分类和分类ID的map集合
//            List<Long> classCodeList = ccCiClassInfos.stream().map(item -> item.getCiClass().getId()).collect(Collectors.toList());
//            CCcCi cc2 = new CCcCi();
//            cc2.setClassId(classCodeList.get(0));
//            List<ESCIInfo> systemExists = iciSwitchSvc.queryESCIInfoList(1L, cc2, null, true, LibType.DESIGN);
//            systemCollect = systemExists.stream().filter(bean->bean.getAttrs().get("CMDB标识ID") != null).collect(Collectors.toMap(bean -> String.valueOf(bean.getAttrs().get("CMDB标识ID")), bean -> bean));
//
//
//        }


        /**
         * 循环遍历assetsAttrDefMap的key,存储所属资产类型的字段对应分类映射数据
         */
        Map<String, Map<String, ESCIInfo>> systemCollectMap = new HashMap<>();
        for(String key : assetsAttrDefMap.keySet()){
            Map<String, ESCIInfo> systemCollect = null;
            CCcCiClass classCdt = new CCcCiClass();

//            classCdt.setId(Long.valueOf(assetsAttrDefMap.get(key)));

            if(category.contains("应用程序") ){
                String extendSystem = CATEGORY_CONFIG.getString("extendSystem");
                if(map.containsKey(extendSystem)){
                    classCdt.setIds(new Long[]{Long.valueOf(assetsAttrDefMap.get(key)),map.get(CATEGORY_CONFIG.getJSONObject("extendSystem")).getCiClass().getId()});

                }else{
                    // 根据视图配置中的配置项获取EA系统中对应的对象分类
                    CCcCiClass classCdtTmp = new CCcCiClass();
                    classCdtTmp.setClassCodes(new String[]{extendSystem});
                    // 查询EA系统中对应的对象分类
                    List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryClassByCdt(classCdtTmp);
                    if (null == ccCiClassInfos || ccCiClassInfos.size() == 0) {
                        log.error("EA系统中不存在[{}]的对象分类", category);
                        classCdt.setId(Long.valueOf(assetsAttrDefMap.get(key)));
//                        return;
                    }else{
                        classCdt.setIds(new Long[]{Long.valueOf(assetsAttrDefMap.get(key)),ccCiClassInfos.get(0).getCiClass().getId()});
                    }

                    // 从对象分类中筛选出分类和分类ID的map集合
//                    Map<String, CcCiClassInfo> map = ccCiClassInfos.stream().collect(Collectors.toMap(item -> item.getCiClass().getClassCode(), item->item));

                }

            }else{
                classCdt.setId(Long.valueOf(assetsAttrDefMap.get(key)));
            }

            // 查询EA系统中对应的对象分类
            List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryClassByCdt(classCdt);

            // 从对象分类中筛选出分类和分类ID的map集合
            List<Long> classCodeList = ccCiClassInfos.stream().map(item -> item.getCiClass().getId()).collect(Collectors.toList());
            CCcCi cc2 = new CCcCi();
//            cc2.setClassId(classCodeList.get(0));
            cc2.setClassIds(classCodeList.toArray(new Long[classCodeList.size()]));
            List<ESCIInfo> systemExists = iciSwitchSvc.queryESCIInfoList(1L, cc2, null, true, LibType.DESIGN);
//            systemCollect = systemExists.stream().filter(bean->bean.getAttrs().get("CMDB标识ID") != null).collect(Collectors.toMap(bean -> String.valueOf(bean.getAttrs().get("CMDB标识ID")), bean -> bean));


             systemCollect = systemExists.stream()
                    .filter(bean -> bean.getAttrs().get("CMDB标识ID") != null)
                    .collect(Collectors.toMap(
                            bean -> String.valueOf(bean.getAttrs().get("CMDB标识ID")),
                            bean -> bean,
                            (existingBean, newBean) -> {
                                //子系统和系统存在重复的系统时，创建时间比较早的删除
                                if (existingBean.getCreateTime().compareTo(newBean.getCreateTime()) > 0) {
                                   iciSwitchSvc.removeByIds(Arrays.asList(newBean.getId()), newBean.getSourceId(), LibType.DESIGN);
                                    return existingBean;
                                } else {
                                   iciSwitchSvc.removeByIds(Arrays.asList(existingBean.getId()), existingBean.getSourceId(), LibType.DESIGN);
                                    return newBean;
                                }
                            }
                    ));
//            iciSwitchSvc.removeById()
            systemCollectMap.put(key,systemCollect);

        }
        log.info("cmdb同步所属资产字段列表-{}",systemCollectMap.keySet());



        List<ESCIInfo> duplicateBeans = new ArrayList<>();

        /**
         * 过滤cmdbid为空的数据，防止非cmdb同步的数据在转map时报错
         */
        Map<String, ESCIInfo> collect = exists.stream()
                .filter(bean->bean.getAttrs().get("CMDB标识ID") != null)
                .collect(Collectors.toMap(
                        bean -> String.valueOf(bean.getAttrs().get("CMDB标识ID")),
                        bean -> bean,
                        (existingBean, newBean) -> {

                            if (existingBean.getCreateTime().compareTo(newBean.getCreateTime()) < 0) {
                                    if(category.contains("应用程序")){
                                        duplicateBeans.add(newBean);
                                    }
                                    return existingBean;
                            }

                            if(category.contains("应用程序")){
                                duplicateBeans.add(existingBean);
                            }

                            return newBean;
                        }
                        )
                );
        //清除应用程序中重复数据的标识id后加入更新列表
        for (ESCIInfo dupBean : duplicateBeans){
            info = dupBean;
            info.setClassId(map.get(category).getCiClass().getId());
            Map<String, Object> mapTmp = info.getAttrs();
            mapTmp.put("CMDB标识ID",null);
            mapTmp.put("应用ID",null);
            info.setAttrs(mapTmp);
            list.add(info);
        }

        deleteCmdbDataByNotExistInCMDB(category,collect,CMDB_DATA_LIST,jsonConfig);


        for (JSONObject object : CMDB_DATA_LIST) {





            String cmdbId = object.getString("instanceId");
            info = collect.get(cmdbId);
            if (null == info) {

                info = new ESCIInfo();
                // 设置CICode唯一ID
                info.setCiCode(String.valueOf(ESUtil.getUUID()));

                info.setAttrs(new HashMap<>());


                /**
                 * 如果有eamid则回写
                 */
                if (object.containsKey("eamId")) {
                    String eamid = object.getString("eamid");
                    if (eamid != null && !eamid.isEmpty()) {
                        /**
                         * 以eamId作为CIId进行查询
                         */
                        CCcCi cdt = new CCcCi();
                        cdt.setCiCode(eamid);

                        List<ESCIInfo>  exist = iciSwitchSvc.queryESCIInfoList(1L, cdt, null, true, LibType.DESIGN);
                        if(exist.size() > 0){
                            info = exist.get(0);
                            log.info("触发cmdb回写");
                        }else {
                            log.error("cmdb会写失败，查询eamid---{}-未找到",eamid);
                            continue;
                        }
                    }
                }
            }

            // 设置分类ID
            info.setClassId(map.get(category).getCiClass().getId());
            attrsMap = Maps.newHashMap();
            Set<String> keys = new HashSet<>(fieldMapping.keySet());
            if(!info.getAttrs().keySet().isEmpty())
            keys.addAll(info.getAttrs().keySet());

            for (String key : keys) {
                if(info.getAttrs() != null && NO_COVER_FIELD.contains(key) && info.getAttrs().containsKey(key) && info.getAttrs().get(key) != null){
                    attrsMap.put(key,info.getAttrs().get(key));
                    continue;
                }


                if (PERSON_FIELD_LIST.contains(key)) {
                    // 对人员相关字段进行处理
                    JSONArray jsonArray = object.getJSONArray(fieldMapping.getString(key));
                    JSONArray personList = new JSONArray();
                    if (null != jsonArray && jsonArray.size() > 0) {
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            JSONObject person = new JSONObject();
                            person.put("loginCode", jsonObject.getString("name"));
                            person.put("userName", StrUtil.isEmpty(jsonObject.getString("nickname")) ? "匿名" : jsonObject.getString("nickname"));
                            personList.add(person);
                        }
                    }
                    attrsMap.put(key, JSON.toJSONString(personList));
                } else if (DEP_FIELD_MAPPING.containsKey(key)) {
                    String currKey = DEP_FIELD_MAPPING.getString(key);
                    JSONArray jsonArray = object.getJSONArray(currKey);
                    String resStr = "";
                    if (null != jsonArray && jsonArray.size() > 0) {
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            if(i != 0){
                                resStr += ",";
                            }
                            resStr += jsonObject.getString("depName");
                        }
                    }
                    attrsMap.put(key,resStr);
                }
//                else if ("所属系统".equals(key) && systemCollect != null) {
//                    JSONArray jsonArray = object.getJSONArray("businesses");
//
//                    String resStr = "";
//                    if (null != jsonArray && jsonArray.size() > 0) {
//                        for (int i = 0; i < jsonArray.size(); i++) {
//                            JSONObject jsonObject = jsonArray.getJSONObject(i);
//                            if(i != 0){
//                                resStr += ",";
//                            }
//                            if(systemCollect.containsKey(jsonObject.getString("instanceId"))){
//                                ESCIInfo tmp = systemCollect.get(jsonObject.getString("instanceId"));
//                                JSONObject res = new JSONObject();
//                                res.put("ciCode",tmp.getCiCode());
//                                res.put("ciLabel",tmp.getCiLabel());
//                                resStr += res.toJSONString();
//                            }
////                            resStr += jsonObject.getString("instanceId");
//                        }
//                    }
//                    attrsMap.put(key,resStr);
//                }
                /**
                 *
                 */
                else if (systemCollectMap.containsKey(key)) {
                    /**
                     * 通过映射读取，判断是否是数组类型，如果是数组进行遍历，否则直接读取
                     */

                    JSONArray jsonArray = object.getJSONArray(fieldMapping.getString(key));

                    log.info("cmdb所属资产字段同步中----{}--{}----{}",key,fieldMapping.getString(key),jsonArray);

                    Map<String, ESCIInfo> systemCollect = systemCollectMap.get(key);
                    String resStr = "";
                    if (null != jsonArray && jsonArray.size() > 0) {
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            if(i != 0){
                                resStr += ",";
                            }
                            /**
                             * 对应用程序进行特殊处理，非父系统时，获取子系统的所属系统
                             */
                            if(!"父系统".equals(jsonObject.getString("_category")) && category.contains("应用程序")){
                                try{
                                    String str = (String) systemCollect.get(jsonObject.getString("instanceId")).getAttrs().get("所属系统");
                                    resStr += str;
                                }catch (Exception e){
                                    log.error("获取所属系统失败-{}",jsonObject.getString("instanceId"));
                                }

                            }
                            else if(systemCollect.containsKey(jsonObject.getString("instanceId"))){
                                try {
                                    ESCIInfo tmp = systemCollect.get(jsonObject.getString("instanceId"));
                                    JSONObject res = new JSONObject();
                                    res.put("ciCode", tmp.getCiCode());
                                    res.put("ciLabel", JSON.parseArray(tmp.getCiLabel()).get(0));
                                    resStr += res.toJSONString();
                                }catch (Exception e){
                                    log.error("获取所属系统失败-{}",jsonObject.getString("instanceId"));
                                }
                            }
                        }
                    }
                    attrsMap.put(key,resStr);
//                    if(category.equals("应用程序")){
//                        JSONArray jsonArray = object.getJSONArray("businesses");
//                        Map<String, ESCIInfo> systemCollect = systemCollectMap.get(key);
//                        String resStr = "";
//                        if (null != jsonArray && jsonArray.size() > 0) {
//                            for (int i = 0; i < jsonArray.size(); i++) {
//                                JSONObject jsonObject = jsonArray.getJSONObject(i);
//                                if(i != 0){
//                                    resStr += ",";
//                                }
//                                /**
//                                 * 如果所属系统不为父系统是子系统，则取所属子系统的所属父系统
//                                 */
//                                if(!"父系统".equals(jsonObject.getString("_category"))){
//                                    String str = (String) systemCollect.get(jsonObject.getString("instanceId")).getAttrs().get("所属系统");
//                                    resStr += str;
//                                } else if(systemCollect.containsKey(jsonObject.getString("instanceId"))){
//                                    ESCIInfo tmp = systemCollect.get(jsonObject.getString("instanceId"));
//                                    JSONObject res = new JSONObject();
//                                    res.put("ciCode",tmp.getCiCode());
//                                    res.put("ciLabel",tmp.getCiLabel());
//                                    resStr += res.toJSONString();
//                                }
////                            resStr += jsonObject.getString("instanceId");
//                            }
//                        }
//                        attrsMap.put(key,resStr);
//                    }
//                    if(category.equals("子系统")){
//                        JSONArray jsonArray = object.getJSONArray("_parent_system");
//                        Map<String, ESCIInfo> systemCollect = systemCollectMap.get(key);
//                        String resStr = "";
//                        if (null != jsonArray && jsonArray.size() > 0) {
//                            for (int i = 0; i < jsonArray.size(); i++) {
//                                JSONObject jsonObject = jsonArray.getJSONObject(i);
//                                if(i != 0){
//                                    resStr += ",";
//                                }
//                               if(systemCollect.containsKey(jsonObject.getString("instanceId"))){
//                                    ESCIInfo tmp = systemCollect.get(jsonObject.getString("instanceId"));
//                                    JSONObject res = new JSONObject();
//                                    res.put("ciCode",tmp.getCiCode());
//                                    res.put("ciLabel",tmp.getCiLabel());
//                                    resStr += res.toJSONString();
//                                }
//                            }
//                        }
//                        attrsMap.put(key,resStr);
//                    }

                }
                else {
                    attrsMap.put(key, object.get(fieldMapping.getString(key)));
                }
            }
            /**
             * todo：处理测试环境cmdb接口的脏数据，防止存储错误，后续可去掉
             */
            if("2".equals(attrsMap.get("系统安全等级"))){
                attrsMap.put("系统安全等级","第二级");
            }
            /**
             * todo:处理结束
             */
            /**
             * 主键为编码类型时，判断原记录是否已经有值，没有值则获取新的编码值
             */
            for (String key : mustAttrDefList) {
                if(info.getAttrs() != null && info.getAttrs().containsKey(key) && info.getAttrs().get(key)!=null){
                    attrsMap.put(key,info.getAttrs().get(key));
                    continue;
                }
                  CcCiAttrDef attrDef;
                  attrDef = attrDefMap.get(key);
                  CiCodeDto ciCodeDto = new CiCodeDto();
                  ciCodeDto.setDefVal(attrDef.getDefVal());
                  ciCodeDto.setClassCode(map.get(category).getCiClass().getClassCode());
                  ciCodeDto.setProName(attrDef.getProName());
//                  ciCodeDto.setStartNum(attrDef.getEnumValues());
                  String enCodeNum = ciClassApiSvc.getEnCodeNum(ciCodeDto);
                  attrsMap.put(key,enCodeNum);

            }



            /**
             * 判断子类是否符合规则要求，符合存入子类
             */
            boolean isMatch = true;
            if(CHILD_RULES_MAP.containsKey(category)){

                Map<String ,String> rules = CHILD_RULES_MAP.get(category);
                for (String key : rules.keySet()) {
                    String value = rules.get(key);
                    if(object.get(key) == null || !object.get(key).equals(value)){
                        isMatch = false;
                    }
//                    System.out.println("Key: " + key + ", Value: " + value);
                }
            }

            /**
             * 判断父类是否不符合子类规则，不符合才存入父类
             */
            if(RULES_MAP.containsKey(category)){
                Map<String ,String> rules = RULES_MAP.get(category);
                for (String key : rules.keySet()) {
                    String value = rules.get(key);
                    if(object.get(key) != null && object.get(key).equals(value)){
                        isMatch = false;
                    }
                }
            }


            /**
             * 判断数据是否符合必填,不符合则过滤掉
             */
            for (String key : isRequiredAttrDefList){
                if(attrsMap.containsKey(key) && attrsMap.get(key)==null){
                    isMatch = false;
                    log.info("{}--过滤不符合必填校验数据-不符合字段【{}】--{}",category,key);
                }
            }


//            Iterator<Map.Entry<String, Object>> iterator = attrsMap.entrySet().iterator();
//            while (iterator.hasNext()) {
//                Map.Entry<String, Object> entry = iterator.next();
//                if (entry.getValue() != null  && "".equals(entry.getValue().toString().trim())) {
//                    entry.setValue(null);
//                }
//                if(entry.getValue() instanceof Date){
//                    if(exitAtrrs.containsKey(entry.getKey()) && exitAtrrs.get(entry.getKey())!=null){
//                        try {
//                            String time = (String) exitAtrrs.get(entry.getKey());
//                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                            Date date = null;
//                            date = sdf.parse(time);
//                            if(date.equals(entry.getValue())){
//                                entry.setValue(time);
//                            }
//                        }catch (Exception e){
//                            log.info("格式化時間異常");
//                        }
//                    }
//                }
//            }

            if(isMatch){
                //如果属性没有变化则跳过
                if (compareMaps(attrsMap, info.getAttrs(),fieldMapping)) {
                    continue;
                }
                info.setAttrs(attrsMap);
                list.add(info);
            }

        }
        return list;
    }

    private boolean compareMaps(Map<String, Object> map1, Map<String, Object> map2,Map<String,Object> fieldMapping) {
        if (map1 == null || map2 == null) {
            return false;
        }
        for (String key : map1.keySet()) {
            if (map2.containsKey(key) && fieldMapping.containsKey(key)) {
                Object value1 = map1.get(key);
                Object value2 = map2.get(key);

                if((isNullOrEmpty(value1) && !isNullOrEmpty(value2))){
                    return false;
                }
                if((!isNullOrEmpty(value1) && isNullOrEmpty(value2))){
                    return false;
                }
                if (value1 != null && value2 != null && !value1.equals(value2)) {
                    if(!(value1 instanceof String)){
                        if(value1.toString().equals(value2)){
                            continue;
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }

    // 判断是否是null和空字符串
    private boolean isNullOrEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof String) {
            return ((String) obj).trim().isEmpty();
        }

        if(obj instanceof JSONArray){
            return ((JSONArray) obj).isEmpty();
        }
        return false;
    }



    /**
     * 删除cdmb中已删除数据
     */
    private  void deleteCmdbDataByNotExistInCMDB(String category, Map<String, ESCIInfo> EaInfo,  List<JSONObject> cmdbInfo,JSONObject jsonConfig) {
        /**
         * 校验分类是否在配置中syncDelCategory配置中,不在则跳过
         */
        JSONArray syncDelCategory = jsonConfig.getJSONArray("syncDelCategory");
        if(syncDelCategory == null) {
            log.error("=====syncDelCategory配置不存在=====，跳过同步删除");
            return;
        }
        /**
         * 防止异常数据，导致全部删除
         */
        if(cmdbInfo.size() == 0) {
            log.error("=====cmdb中数据为空=====，跳过同步删除");
            return;
        }
        AtomicReference<Boolean> flag = new AtomicReference<>(false);
        syncDelCategory.forEach(item -> {
            if(item.equals(category)){
                flag.set(true);
            }
        });
        if(!flag.get()){
            return;
        }
        log.info("开始同步删除，分类-{}",category);

        /**
         * 过滤出eaInfo中在cmdb中不存在的数据,并删除
         */
        try{
            Set<String> cmdbSet = cmdbInfo.stream().map(bean -> bean.getString("instanceId")).collect(Collectors.toSet());
            List<Long> delList = new ArrayList<>();
            for (ESCIInfo info : EaInfo.values()){
                if(!cmdbSet.contains(String.valueOf(info.getAttrs().get("CMDB标识ID")))){
                    log.info("删除cmdb已删除数据---{}",info.getAttrs());
                    delList.add(info.getId());
                }
            }
            iciSwitchSvc.removeByIds(delList,null,LibType.DESIGN);
        }catch (Exception e){
            log.error("删除cmdb已删除数据失败",e);
        }


    }


    /**
     * 本地测试数据
     *
     * @return
     */
    private void localTestData() {
        String s1 = "{\"number\":\"T-test003\",\"instanceId\":\"5e0e5c82d92da\",\"businessId\":\"5e0e5c82d92da\",\"name\":\"test系统3\",\"sysState\":\"已上线\",\"_object_id\":\"BUSINESS\",\"operationManager\":[],\"owner\":[],\"systemManager\":[],\"backupOps\":[]}";
        String s2 = "{\"maintenceState\":\"运维中\",\"level\":\"B1\",\"businessId\":\"5d87d2e49d59f\",\"_object_id\":\"BUSINESS\",\"starttime\":\"2022-02-28\",\"securityLevel\":\"第二级\",\"number\":\"S448\",\"instanceId\":\"5d87d2e49d59f\",\"buildType\":\"自主研发\",\"isImportant\":\"否\",\"name\":\"自营OneQuant量化投资交易系统\",\"_category\":\"父系统\",\"sysState\":\"已上线\",\"describe\":\"系统描述：自营OneQuant系统是量化投资部、金融衍生品部用于对自营O32系统中产品账户进行算法拆单服务及交易策略执行的系统。技术机构复用原有OneQuant系统，由于监管合规要求，独立部署上线。\",\"shortName\":\"OQZY\",\"operationManager\":[{\"_object_version\":413,\"creator\":\"defaultUser\",\"updateAuthorizers\":[],\"org\":3103,\"user_tel\":\"easyops\",\"modifier\":\"rdm\",\"_object_id\":\"USER\",\"mtime\":\"2023-11-16 15:07:43\",\"isOa\":\"是\",\"dep\":\"管理员 示例部门\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"59485dd0ac052\",\"deleteAuthorizers\":[],\"name\":\"easyops\",\"nickname\":\"easyops\",\"ctime\":\"2019-10-10 11:19:03\",\"state\":\"valid\",\"_version\":7,\"_pre_ts\":1623895346,\"_ts\":1700118463},{\"_object_version\":413,\"creator\":\"defaultUser\",\"updateAuthorizers\":[],\"user_email\":\"jiangzy1@essence.com.cn\",\"org\":3103,\"modifier\":\"rdm\",\"_object_id\":\"USER\",\"mtime\":\"2023-11-13 16:56:32\",\"isOa\":\"是\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"5d818a07dddd3\",\"deleteAuthorizers\":[],\"name\":\"jiangzy1\",\"nickname\":\"江正煜\",\"ctime\":\"2022-02-16 09:32:46\",\"state\":\"valid\",\"_version\":4,\"_pre_ts\":1653897383,\"_ts\":1699865792}],\"owner\":[{\"_object_version\":413,\"creator\":\"defaultUser\",\"updateAuthorizers\":[],\"user_email\":\"jiangzy1@essence.com.cn\",\"org\":3103,\"modifier\":\"rdm\",\"_object_id\":\"USER\",\"mtime\":\"2023-11-13 16:56:32\",\"isOa\":\"是\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"5d818a07dddd3\",\"deleteAuthorizers\":[],\"name\":\"jiangzy1\",\"nickname\":\"江正煜\",\"ctime\":\"2022-02-16 09:32:46\",\"state\":\"valid\",\"_version\":4,\"_pre_ts\":1653897383,\"_ts\":1699865792}],\"systemManager\":[{\"_object_version\":413,\"creator\":\"defaultUser\",\"updateAuthorizers\":[],\"user_email\":\"jiangzy1@essence.com.cn\",\"org\":3103,\"modifier\":\"rdm\",\"_object_id\":\"USER\",\"mtime\":\"2023-11-13 16:56:32\",\"isOa\":\"是\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"5d818a07dddd3\",\"deleteAuthorizers\":[],\"name\":\"jiangzy1\",\"nickname\":\"江正煜\",\"ctime\":\"2022-02-16 09:32:46\",\"state\":\"valid\",\"_version\":4,\"_pre_ts\":1653897383,\"_ts\":1699865792}],\"backupOps\":[{\"_object_version\":413,\"creator\":\"defaultUser\",\"updateAuthorizers\":[],\"user_email\":\"111@163.com\",\"org\":3103,\"modifier\":\"rdm\",\"_object_id\":\"USER\",\"mtime\":\"2023-11-16 15:07:43\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"59796410d63e8\",\"deleteAuthorizers\":[],\"name\":\"younuo\",\"nickname\":\"优锘\",\"ctime\":\"2019-11-18 11:07:55\",\"state\":\"valid\",\"_version\":3,\"_pre_ts\":1681869126,\"_ts\":1700118463},{\"_object_version\":57,\"creator\":\"easyops\",\"updateAuthorizers\":[],\"user_email\":\"quanns@essence.com.cn\",\"org\":3103,\"user_tel\":\"?\",\"modifier\":\"lonlin\",\"_object_id\":\"USER\",\"mtime\":\"2022-05-30 15:56:21\",\"isOa\":\"是\",\"readAuthorizers\":[],\"_schema_groups\":[],\"instanceId\":\"5a137470d5b58\",\"deleteAuthorizers\":[],\"name\":\"quanns\",\"nickname\":\"权宁升\",\"ctime\":\"2020-03-20 00:01:10\",\"state\":\"valid\",\"_version\":7,\"_pre_ts\":1649233874,\"_ts\":1653897381}]}";
        JSONObject json1 = JSONObject.parseObject(s1);
        JSONObject json2 = JSONObject.parseObject(s2);
        List<JSONObject> list = new ArrayList<>();
        list.add(json1);
        list.add(json2);
        /*for (int i = 0; i < 20; i++) {
            JSONObject object = new JSONObject();
            object.put("name", "系统名称" + i);
            object.put("number", "系统编号" + i);
            object.put("sysState", "系统状态" + i);
            object.put("shortName", "系统简称" + i);
            object.put("starttime", "系统上线时间" + i);
            object.put("endtime", "系统下线时间" + i);
            object.put("buildType", "建设类型" + i);
            object.put("maintenceState", "运维状态" + i);
            object.put("isImportant", "是否为重要系统" + i);
            object.put("buildYear", "建设年份" + i);
            object.put("_category", "是否子系统" + i);
            object.put("secueitylevel", "系统安全事件定级分类" + i);
            object.put("level", "保障等级" + i);
            object.put("securityLevel", "系统安全等级" + i);
            object.put("problemability", "信息系统备份能力" + i);
            object.put("applicationArea", "应用领域" + i);
            object.put("servicestarttime", "主要服务时间(开始)" + i);
            object.put("serviceendtime", "主要服务时间(结束)" + i);
            object.put("businessLine", "业务线" + i);
            object.put("xc", "新创适配" + i);
            object.put("testManageType", "测试管理类别" + i);
            object.put("describe", "系统描述" + i);
            object.put("memo", "备注" + i);
            object.put("businessanddisc", "主要业务及分配比例描述" + i);
            object.put("usability", "可用性目标" + i);
            object.put("rpo", "恢复点目标（PRO）" + i);
            object.put("rto", "恢复时间目标（PTO）" + i);
            object.put("systemAlias", "系统代称" + i);
            object.put("mbco", "MBCO（最低业务持续目标）" + i);
            object.put("domain", "主用域名" + i);
            object.put("clusterType", "部署架构类型" + i);
            object.put("logicPhoto", "逻辑架构图" + i);
            object.put("type", "系统类型" + i);
            object.put("bia", "商业影响分析" + i);
            object.put("demanddepartment", "需求部门" + i);
            object.put("servicetime", "服务时间" + i);
            object.put("isrealtime", "是否实时" + i);
            object.put("istransaction", "是否交易" + i);
            object.put("systemclassification", "系统分类" + i);
            object.put("businessId", "业务ID" + i);
            object.put("_catagory", "业务分类" + i);
            object.put("isLeaf", "叶子节点" + i);
            object.put("importentAndReport", "重要且报送" + i);
            object.put("isdiagram", "架构可视化是否单独绘图" + i);
            object.put("systemcoupling", "系统耦合关系" + i);
            object.put("possibleimpact", "可能产生影响程度" + i);
            object.put("delete", "pms上已删除" + i);
            object.put("backupinfo", "备份信息" + i);
            object.put("operation", "运维信息" + i);
            object.put("usesercet", "使用密码设备" + i);
            object.put("developerleader", "供应商负责人" + i);
            object.put("supperlier", "供应商" + i);
            object.put("tenumber", "供应商联系电话" + i);
            object.put("outsource", "外包情况" + i);
            object.put("email", "供应商联系邮箱" + i);
            object.put("mainMiddleware", "主要中间件" + i);
            object.put("systemversion", "系统版本" + i);
            object.put("wdbs", "部署网段" + i);
            object.put("xtjg", "系统架构" + i);
            object.put("usersize", "用户规模" + i);
            object.put("serviceobjectcategory", "服务对象类别" + i);
            object.put("serviceobject", "客户群体" + i);
            object.put("isTransaction", "是否交易系统" + i);
            object.put("isRealTime", "是否实时系统" + i);
            object.put("testFields", "测试字段" + i);
            object.put("archPhoto", "架构图链接" + i);
            object.put("disasterCapability", "灾难应对能力" + i);
            object.put("suppliertel", "供应商负责人电话" + i);
            object.put("outsourcesupplier", "系统外包供应商" + i);
            object.put("biaBusinessLine", "BIA业务线" + i);
            object.put("faultCapability", "故障应用能力" + i);
            object.put("dataBackup", "数据备份能力" + i);
            object.put("doo", "操作说明" + i);
            object.put("majorDisasterCapability", "重大灾难应对能力" + i);
            list.add(object);
        }*/
        CMDB_DATA_LIST = list;
    }

}
